﻿using System;
using System.Collections.Generic;
using System.Linq;
using Hangfire;
using Hangfire.RecurringJobExtensions;
using Hangfire.Server;
using Identification.Importer.Core.Entity;
using Identification.Importer.Core.Filter;
using Identification.Importer.Core.Setting;
using Microsoft.Extensions.Logging;
using MongoDB.Bson;
using MongoDB.Driver;

namespace Identification.Importer.Core.Job
{
    public class GIdAssociationFanJob : BaseProcessor<BsonDocument, GIdAssociationFanModel>, IRecurringJob
    {
        private readonly GIdAssociationFanSetting _setting;

        public GIdAssociationFanJob(GIdAssociationFanSetting setting, ILoggerFactory loggerFactory) : base(setting)
        {
            _setting = setting;
            Logger = loggerFactory.CreateLogger<GIdAssociationFanJob>();
        }

        [LogEverything]
        [AutomaticRetry(Attempts = 0)]
        [DisableConcurrentExecution(36000)]
        public void Execute(PerformContext context)
        {
            var flag = true;
            do
            {
                RetryWorker.Execute(() =>
                {
                    this.Timestamp = DateTime.UtcNow;

                    var projection = new BsonDocument
                    {
                        {"_id", 1},
                        {"FanId", 1},
                        {"Mobile", 1}
                    };

                    var filter = Builders<BsonDocument>.Filter.Eq("IsDeleted", false);
                    if (!string.IsNullOrWhiteSpace(_setting.SourceLatestObjectId))
                    {
                        if (ObjectId.TryParse(_setting.SourceLatestObjectId, out var objectId))
                        {
                            filter = filter & Builders<BsonDocument>.Filter.Gt("_id", objectId);
                        }
                    }

                    var sorter = Builders<BsonDocument>.Sort.Ascending("_id");

                    var docs = SourceCollection.Find(filter).Project(projection).Sort(sorter)
                        .Limit(_setting.SourceQueryLimit).ToList();

                    if (!docs.Any())
                    {
                        flag = false;
                        return;
                    }

                    var models = new List<GIdAssociationFanModel>();
                    foreach (var doc in docs)
                    {
                        doc.TryGetValue("FanId", out var fanId);
                        doc.TryGetValue("Mobile", out var mobile);

                        var globalId = FetchGlobalId(null, mobile == null ? null : mobile.ToString());

                        if (globalId == Error)
                        {
                            Logger.LogError("can not fetch globalId, setting:{setting},doc:{doc}",
                                _setting,
                                doc.ToDictionary());
                            continue;
                        }

                        var model = new GIdAssociationFanModel()
                        {
                            CreateTime = this.Timestamp,
                            FanId = (fanId ?? "").ToString(),
                            GlobalId = globalId
                        };

                        models.Add(model);
                    }

                    TargetCollection.InsertMany(models);
                    _setting.SourceLatestObjectId = docs.LastOrDefault()?["_id"].ToString();
                });
            } while (flag);
        }
    }
}